package com.yilijk.base.network.https;

import android.os.Message;

import com.alibaba.android.arouter.launcher.ARouter;
import com.yilijk.base.BaseApi;
import com.yilijk.base.AppBase;
import com.yilijk.base.network.RequestMethod;
import com.yilijk.base.network.RequestParams;
import com.yilijk.base.network.config.BaseUrl;
import com.yilijk.base.network.config.BaseRouter;
import com.yilijk.base.network.core.CallEntity;
import com.yilijk.base.network.core.NetWorkService;
import com.yilijk.base.network.core.NetworkCallback;
import com.yilijk.base.network.core.RetrofitManager;
import com.yilijk.base.network.error.HttpErrorCode;
import com.yilijk.base.oss.UploadOssUtils;
import com.yilijk.base.utils.ALog;
import com.yilijk.base.utils.CommonUtils;
import com.yilijk.base.utils.DevicesUtils;
import com.yilijk.base.utils.FileUtils2;
import com.yilijk.base.utils.MapRemoveNullUtil;
import com.yilijk.base.utils.NetworkUtils;
import com.yilijk.base.utils.UrlSignUtils;

import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.Route;
import retrofit2.Call;

/**
 * Created by SHICHENG
 * 网络请求Https工具
 * Time on 2022/03/07
 */
public class HttpUtils {

    private static ArrayList<WeakReference<CallEntity<?>>> mCallEntity = new ArrayList<>();

    private HttpUtils() {
    }

    /**
     * post 请求
     *
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> post(String url, RequestParams params, HttpCallBack<T> httpListener) {

        return bodyMethod(RequestMethod.POST, url, params, httpListener);

    }

    public static <T> CallEntity<T> post(String url, HttpCallBack<T> httpListener) {
        return post(url, new RequestParams(), httpListener);

    }

    /**
     * PUT请求
     *
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> put(String url, RequestParams params, HttpCallBack<T> httpListener) {
        return bodyMethod(RequestMethod.PUT, url, params, httpListener);

    }


    /**
     * GET请求
     *
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> get(String url, RequestParams params, HttpCallBack<T> httpListener) {
        return queryMethod(RequestMethod.GET, url, params, httpListener);
    }

    /**
     * GET请求 不带参数
     *
     * @param url          https:\\或http：\\或不带
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> get(String url, HttpCallBack<T> httpListener) {
        return get(url, new RequestParams(), httpListener);
    }


    /**
     * DELETE 请求
     *
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> delete(String url, RequestParams params, HttpCallBack<T> httpListener) {
        return queryMethod(RequestMethod.DELETE, url, params, httpListener);
    }


    /**
     * 单文件上传
     *
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param filepath     单文件
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> uploadFile(String url, RequestParams params, String filepath, HttpCallBack<T> httpListener) {
        if (isNotConnected(httpListener)) {
            return buildEmptyCallEntity();
        }

        Call<ResponseBody> responseBody;
        String uri2Path = null;
        if (filepath.charAt(0) != '/') {
            uri2Path = FileUtils2.uri2Path(AppBase.getApplication(), uri2Path);
        } else {
            uri2Path = filepath;
        }
        File file = new File(uri2Path);
        RequestBody requestFile = RequestBody.create(file, MediaType.parse("multipart/form-data"));
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestFile);

        HashMap<String, RequestBody> partMap = new HashMap<>();
        if (params != null) {
            Iterator<String> iterator = params.keys();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String value = params.optString(key);
                RequestBody body = RequestBody.create(value, MediaType.parse("multipart/form-data"));
                partMap.put(key, body);
            }
        }

        NetWorkService workService = RetrofitManager.getRetrofitManager().getRetrofit().create(NetWorkService.class);
        responseBody = workService.upLoadFile(url, partMap, filePart);
        if (responseBody != null) {
            responseBody.enqueue(new NetworkCallback<>(httpListener));
        }
        return buildCallEntity(responseBody, httpListener);
    }


    public static <T> CallEntity<T> uploadFile2Oss(File file,HttpCallBack<T> httpListener){
        Call<ResponseBody> responseBodyCall = null;
        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        String newName = file.getName().replace("_", "");
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file",newName, requestFile);

        JSONObject upLoadParams = UploadOssUtils.getInstance().getUpLoadParams("android/"+getOssPath()+"/image", newName);
        if (upLoadParams == null) {
            UploadOssUtils.getInstance().init();
            return null;
        }
        if (UploadOssUtils.getInstance().getData().getOssHost().startsWith("http:")) {
            String replace = UploadOssUtils.getInstance().getData().getOssHost().replace("http", "https");
            responseBodyCall = RetrofitManager.getRetrofitManager().getRetrofit()
                    .create(NetWorkService.class)
                    .upLoadImg(replace,
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getPolicy()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getAccessKeyId()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getSignature()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getStartWith() + "android/"+getOssPath()+"/image/" + newName),
                            RequestBody.create(MediaType.parse("multipart/form-data"), "200"),
                            filePart);
        } else {
            responseBodyCall = RetrofitManager.getRetrofitManager().getRetrofit()
                    .create(NetWorkService.class)
                    .upLoadImg(UploadOssUtils.getInstance().getData().getOssHost(),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getPolicy()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getAccessKeyId()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getSignature()),
                            RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getStartWith() + "android/"+getOssPath()+"/image/" + newName),
                            RequestBody.create(MediaType.parse("multipart/form-data"), "200"),
                            filePart);
        }
        if (responseBodyCall != null) {
            responseBodyCall.enqueue(new NetworkCallback<>(httpListener));
        }
        return buildCallEntity(responseBodyCall, httpListener);
    }


    public static <T> CallEntity<T> uploadAmr2Oss(File file,HttpCallBack<T> httpListener){
        Call<ResponseBody> responseBodyCall = null;
        if (!DevicesUtils.getToken().isEmpty()) {
            RequestBody requestFile = RequestBody.create(MediaType.parse("audio/mp3"), file);
            String newName = file.getName().replace("_", "");
            MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", newName, requestFile);
            JSONObject upLoadParams = UploadOssUtils.getInstance().getUpLoadParams("android/"+getOssPath()+"/file", newName);
            if (upLoadParams == null) {
                UploadOssUtils.getInstance().init();
                return null;
            }
            if (UploadOssUtils.getInstance().getData().getOssHost().startsWith("http:")) {
                String replace = UploadOssUtils.getInstance().getData().getOssHost().replace("http", "https");
                responseBodyCall = RetrofitManager.getRetrofitManager()
                        .getRetrofit()
                        .create(NetWorkService.class)
                        .upLoadMP3(replace,
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getPolicy()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getAccessKeyId()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getSignature()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getStartWith() + "android/"+getOssPath()+"/file/" + newName),
                                RequestBody.create(MediaType.parse("multipart/form-data"), "200"),
                                filePart);
            } else {
                responseBodyCall = RetrofitManager.getRetrofitManager()
                        .getRetrofit()
                        .create(NetWorkService.class)
                        .upLoadMP3(UploadOssUtils.getInstance().getData().getOssHost(),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getPolicy()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getAccessKeyId()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getSignature()),
                                RequestBody.create(MediaType.parse("multipart/form-data"), UploadOssUtils.getInstance().getData().getStartWith() + "android/"+getOssPath()+"/file/" + newName),
                                RequestBody.create(MediaType.parse("multipart/form-data"), "200"),
                                filePart);
            }
            if (responseBodyCall!=null){
                responseBodyCall.enqueue(new NetworkCallback<>(httpListener));
            }
        }
        return buildCallEntity(responseBodyCall, httpListener);
    }

    public static <T> CallEntity<T> uploadAmr(String url,File file,HttpCallBack<T> httpListener){
        Call<ResponseBody> responseBodyCall = null;
        if (!DevicesUtils.getToken().isEmpty()) {
            RequestBody requestFile = RequestBody.create(MediaType.parse("audio/mp3"), file);
            MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
            responseBodyCall = RetrofitManager.getRetrofitManager().getRetrofit().create(NetWorkService.class).upLoadMP3(url, filePart);
        }
        if (responseBodyCall!=null){
            responseBodyCall.enqueue(new NetworkCallback<>(httpListener));
        }
        return buildCallEntity(responseBodyCall, httpListener);
    }

    /**
     *
     * @param downUrl
     * @param httpListener
     * @return
     */
    public static <T> void downloadFile(String downUrl, String savaPath,String fileName, HttpCallBack<T> httpListener){
        CommonUtils.getModuleCommonUtils().getExecutorService().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(downUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    final int contentLength = connection.getContentLength();//文件大小
//                    allSize.setText(contentLength+"");
//                    dialogProgress.setMax(contentLength);
                    InputStream inputStream = connection.getInputStream();
                    File file = new File(savaPath);
                    if (!file.exists()) {
                        file.mkdir();
                    }
                    String apkFile = savaPath+fileName;
                    File apkfile = new File(apkFile);
                    FileOutputStream fileOutputStream = new FileOutputStream(apkFile);
                    int count = 0;
                    int lenth = 0;
                    byte[] bytes = new byte[512];
                    while ((lenth = inputStream.read(bytes)) != -1) {
                        count += lenth;
                        fileOutputStream.write(bytes, 0, lenth);
                        Message message = new Message();
                        message.arg1 = count;
                        message.arg2 = contentLength;
                        message.what = 2;
                        fileOutputStream.flush();

                    }
                    httpListener.onSuccess(null, 200);
                    fileOutputStream.close();
                    inputStream.close();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    httpListener.onFailure("error",404);
                } catch (IOException e) {
                    e.printStackTrace();
                    httpListener.onFailure("error",404);
                }
            }
        });
    }

    /**
     * 带BODY的请求
     *
     * @param method       {@link RequestMethod#PUT}{@link RequestMethod#POST}
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    private static <T> CallEntity<T> bodyMethod(String method, String url, RequestParams params, HttpCallBack<T> httpListener) {
        if (isNotConnected(httpListener)) {
            return buildEmptyCallEntity();
        }

        HashMap<String, Object> deviceInfo = DevicesUtils.addDeviceInfo(new HashMap<>());
        if (params == null) {
            params = new RequestParams();
        }

        for (Map.Entry<String, Object> entry : deviceInfo.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            params.put(key, value);
        }

        if (isSign(url)){
            //部分接口带签名
            UrlSignUtils.sign(params);
        }

        String paramsString = params.toString();

        url = buildUrl(url);

        RequestBody body = RequestBody.create(paramsString, MediaType.parse("application/json;charset=UTF-8"));

        NetWorkService service = RetrofitManager.getRetrofitManager().getRetrofit().create(NetWorkService.class);

        Call<ResponseBody> responseBody = null;
        switch (method.toUpperCase(Locale.ROOT)) {
            case RequestMethod.POST:
                responseBody = service.post(url, body);
                break;
            case RequestMethod.PUT:
                responseBody = service.put(url, body);
                break;
            default:
                break;
        }
        if (responseBody != null) {
            responseBody.enqueue(new NetworkCallback<>(httpListener));
        }

        return buildCallEntity(responseBody, httpListener);
    }


    /**
     * 拼接参数的请求
     *
     * @param method       {@link RequestMethod#GET}{@link RequestMethod#DELETE}
     * @param url          https:\\或http：\\或不带
     * @param params       参数
     * @param httpListener 监听
     * @return CallEntity
     */
    public static <T> CallEntity<T> queryMethod(String method, String url, RequestParams params, HttpCallBack<T> httpListener) {
        if (isNotConnected(httpListener)) {
            return buildEmptyCallEntity();
        }

        HashMap<String, Object> deviceInfo = DevicesUtils.addDeviceInfo(new HashMap<>());
        HashMap<String, Object> queryMap = new HashMap<>(deviceInfo);

        if (params != null) {
            Iterator<String> paramsKeys = params.keys();
            while (paramsKeys.hasNext()) {
                String key = paramsKeys.next();
                String value = params.optString(key);
                queryMap.put(key, value);
            }
        }

        MapRemoveNullUtil.removeNullKey(queryMap);
        MapRemoveNullUtil.removeNullValue(queryMap);

        url = buildUrl(url);
        NetWorkService service = RetrofitManager.getRetrofitManager().getRetrofit().create(NetWorkService.class);

        Call<ResponseBody> responseBody = null;
        switch (method.toUpperCase(Locale.ROOT)) {
            case RequestMethod.DELETE:
                responseBody = service.delete(url, queryMap);
                break;
            case RequestMethod.GET:
                responseBody = service.get(url, queryMap);
                break;
            default:
                break;
        }

        if (responseBody != null) {
            responseBody.enqueue(new NetworkCallback<>(httpListener));
        }

        return buildCallEntity(responseBody, httpListener);
    }


    /**
     * 用于取消请求
     */
    private static <T> CallEntity<T> buildCallEntity(Call<ResponseBody> responseBodyCall, HttpCallBack<T> netWorkListener) {
        CallEntity<T> callEntity = new CallEntity<>(responseBodyCall, netWorkListener);
        if (mCallEntity == null) {
            mCallEntity = new ArrayList<>();
        }
        mCallEntity.add(new WeakReference<>(callEntity));
        return callEntity;
    }

    /**
     * 用于取消请求
     */
    private static <T> CallEntity<T> buildEmptyCallEntity() {
        return buildCallEntity(null, null);
    }

    /**
     * 取消请求
     *
     * @param tag 对应的标签
     */
    public static void cancel(String tag) {
        if (mCallEntity != null) {
            for (WeakReference<CallEntity<?>> call : mCallEntity) {
                CallEntity<?> callEntity = call.get();
                if (callEntity != null && tag != null && !tag.isEmpty() && tag.equals(callEntity.getCancelTag())) {
                    WeakReference<Call<ResponseBody>> callWeakReference = callEntity.getCallWeakReference();
                    Call<ResponseBody> bodyCall = callWeakReference.get();
                    if (bodyCall != null) {
                        ALog.i(tag + ":cancel");
                        bodyCall.cancel();
                        callEntity.setNetWorkListener(null);
                        call.clear();
                    }
                }
            }
        }
    }

    /**
     * 全部请求取消
     */
    public static void cancelAll() {
        if (mCallEntity != null) {
            for (WeakReference<CallEntity<?>> call : mCallEntity) {
                CallEntity<?> callEntity = call.get();
                if (callEntity != null) {
                    WeakReference<Call<ResponseBody>> callWeakReference = callEntity.getCallWeakReference();
                    Call<ResponseBody> bodyCall = callWeakReference.get();
                    if (bodyCall != null) {
                        ALog.i("cancel:" + callEntity.getCancelTag());
                        bodyCall.cancel();
                        callEntity.setNetWorkListener(null);
                        call.clear();
                    }
                }
            }
        }
    }


    /**
     * 检测是否没有网络
     *
     * @param httpListener 监听返回
     * @return true 没有网络
     */
    private static <T> boolean isNotConnected(HttpCallBack<T> httpListener) {
        if (!NetworkUtils.isConnected()) {
            try {
                httpListener.onFailure("", HttpErrorCode.NETWORK_DISCONNECTED);
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                httpListener.onComplete();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }


    private static String buildUrl(String path) {
        String url = getUrl();

        if (!path.startsWith("http") || !path.startsWith("https")) {
            if (!url.endsWith("/") && !path.startsWith("/")) {
                url += "/";
            }
            path = url + path;
        }

        return path;
    }

    /**
     * url都从主项目获取
     *
     * @return url
     */
  

    public static String getUrl() {
        BaseApi baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        return baseApi.getDomin();
//        return getEnvironmentNo() == 0 ? BaseUrl.DOMIN.d1 :
//                getEnvironmentNo() == 1 ? BaseUrl.DOMIN.t1 :
//                        getEnvironmentNo() == 2 ? BaseUrl.DOMIN.pre :
//                                BaseUrl.DOMIN.api;
    }

    public static String getWebUrl(){
        BaseApi baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        return baseApi.getWebUrl();
//        return getEnvironmentNo() == 0 ? BaseUrl.WEB.d1 :
//                getEnvironmentNo() == 1 ? BaseUrl.WEB.t1 :
//                        getEnvironmentNo() == 2 ? BaseUrl.WEB.pre :
//                                BaseUrl.WEB.api;
    }

    public static String getH5Url(){
        BaseApi baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        return baseApi.getH5Url();
//        return getEnvironmentNo() == 0 ? BaseUrl.H5.d1 :
//                getEnvironmentNo() == 1 ? BaseUrl.H5.t1 :
//                        getEnvironmentNo() == 2 ? BaseUrl.H5.pre :
//                                BaseUrl.H5.api;
    }

    public static String getPointUrl(){
        BaseApi baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        return baseApi.getPointUrl();
//        return getEnvironmentNo() == 0 ||
//                getEnvironmentNo() == 1 ? BaseUrl.POINT.t1 :
//                BaseUrl.POINT.api;
    }

    public static int getEnvironmentNo(){
        baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        int dominNo = baseApi.getDominNo();
        ALog.i("getEnvironmentNo",dominNo+"");
        return dominNo;
    }
    
    private static BaseApi baseApi;
    private static boolean isSign(String url){
        baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        for (String s:baseApi.noSign()
             ) {
            if (!url.contains(s)) {
                return false;
            }
        }
        return true;
    }

    private static String getOssPath(){
        BaseApi baseApi = (BaseApi) ARouter.getInstance().build(BaseRouter.Base).navigation();
        return baseApi.getOssPath();
    }

}


